package admin

import (
	"fmt"
	"github.com/dgrijalva/jwt-go"
	"github.com/gin-contrib/cors"
	"github.com/gin-gonic/gin"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"github.com/sirupsen/logrus"
	"go-proxy/admin/controller"
	"go-proxy/admin/vo"
	"go-proxy/common"
	"go-proxy/config"
	"go-proxy/util"
	"log"
	"strings"
	"time"
)

func ConsoleServe() {
	adminConfig := config.Config.Admin
	router := gin.Default()

	corsConfig := cors.DefaultConfig()
	corsConfig.AllowAllOrigins = true
	router.Use(cors.New(corsConfig))
	router.Use(GinAuth(adminConfig.Secret))
	router.Use(GinLogger(common.Logger))

	router.GET("/metrics", gin.WrapH(promhttp.Handler()))
	router.Static("/static", "./dist")

	authRouter := router.Group("/auth")
	{
		authRouter.POST("/login", controller.Login)
		authRouter.GET("/userInfo", controller.GetUserInfo)
	}

	proxyRouter := router.Group("/proxy")
	{
		proxyRouter.GET("/restart", controller.RestartServer)
		proxyRouter.GET("/servers", controller.ServerList)
		proxyRouter.GET("/stop", controller.StopServer)
	}

	homeRouter := router.Group("/home")
	{
		homeRouter.GET("/overView", controller.GetOverView)
	}

	common.LogInfo("管理后台运行成功: port=", adminConfig.Port)
	err := router.Run(fmt.Sprintf(":%d", adminConfig.Port))
	if err != nil {
		common.LogError("管理后台运作失败 error:", err)
	}
}

// GinLogger 返回一个Gin中间件，用于将请求日志记录到
func GinLogger(logger *logrus.Logger) gin.HandlerFunc {
	return func(c *gin.Context) {
		// 开始时间
		startTime := time.Now()

		// 处理请求
		c.Next()

		// 结束时间
		endTime := time.Now()
		costTime := endTime.Sub(startTime)

		// 日志格式
		logger.WithFields(logrus.Fields{
			"status": c.Writer.Status(),
			"method": c.Request.Method,
			"path":   c.Request.URL.Path,
			"cost":   costTime.Milliseconds(),
			"ip":     c.ClientIP(),
		}).Info("admin request")
	}
}

func GinAuth(secret string) gin.HandlerFunc {
	return func(c *gin.Context) {
		path := c.Request.URL.Path
		if common.NoAuthPath[path] || strings.HasPrefix(path, "/static") {
			c.Next()
			return
		}

		log.Println("AuthHandler path:", path)
		tokenString := c.GetHeader(common.AUTHORIZATION)
		log.Println("路由鉴权处理 token=", tokenString)

		token, err := util.ValidateToken(tokenString, secret)
		if err != nil {
			c.Abort()
			vo.Fail(c, vo.ErrAuth)
			return
		}

		if claims, ok := token.Claims.(jwt.MapClaims); ok {
			username := claims[common.USERNAME].(string)
			c.Set(common.USERNAME, username)
		}
		c.Next()
	}
}
